"""
Case Type   : CM_Tools
Case Name   : 故障测试，主节点信号量测试(9)
Create At   : 2025/5/22
Owner       : ningyali
Description :
    1.主节点执行业务
    2.查看集群状态
    3.kill -9强制终止数据库进程
    4.查看集群状态
    5.查看主节点事务执行情况
Expect      :
    1.执行成功
    2.执行成功
    3.强制终止数据库主进程成功
    4.数据库主节点已被拉起
    5.主节点事务阻塞
History     :
"""

import os
import re
import time
import unittest

from testcase.utils.ComInstall import CmInstall
from testcase.utils.ComInstall import CmUnInstall
from testcase.utils.Common import Common
from testcase.utils.CommonSH import CommonSH
from testcase.utils.Constant import Constant
from testcase.utils.ComThread import ComThread
from testcase.utils.Logger import Logger
from yat.test import Node
from yat.test import macro


class CMServer(unittest.TestCase):
    def setUp(self):
        self.log = Logger()
        self.log.info(f'-----{os.path.basename(__file__)} start-----')
        self.pri_sh = CommonSH('PrimaryDbUser')
        self.root_nodes = (Node('PrimaryRoot'), Node('Standby1Root'),
                           Node('Standby2Root'))
        self.user_nodes = (Node('PrimaryDbUser'), Node('Standby1DbUser'),
                           Node('Standby2DbUser'))
        self.common = Common()
        self.constant = Constant()
        self.t_name = 't_cm_tools_0019'
        self.q_cmd = f"source {macro.DB_ENV_PATH};cm_ctl query -v -C -i -d"
        self.ps_cmd = f'ps ux|grep -v grep|grep gaussdb|' \
                      f'grep {macro.DB_INSTANCE_PATH}'

        text = '----prestep1:安装cm;expect:执行成功----'
        self.log.info(text)
        self.install_pkg_path = os.path.dirname(macro.DB_SCRIPT_PATH)
        self.cm = CmInstall(self.install_pkg_path, self.pri_sh.node.ssh_user)
        res = self.cm.update_xml_for_cm(*self.root_nodes)
        self.assertGreater(res.count('cmDir'), 1, f'执行失败: {text}')

        res = self.cm.cm_install(self.user_nodes[0])
        self.assertIn('Install CM tool success', res, f'执行失败: {text}')

    def test_trans(self):
        text = '----step1:主节点执行业务;expect:执行成功----'
        self.log.info(text)
        sql = f"create table {self.t_name}(id int,name varchar(100));" \
              f"insert into {self.t_name} values(generate_series(1,1000)," \
              f"'a_'||generate_series(1,1000));" \
              f"update {self.t_name} set name='cm' where id<200;" \
              f"delete from {self.t_name};" \
              f"select count(*) from {self.t_name};" \
              f"drop table {self.t_name} cascade;"
        pri_thread = ComThread(self.pri_sh.cycle_exec_sql,
                               args=(sql, 50, False, None, True))
        pri_thread.setDaemon(True)
        pri_thread.start()

        text = '----step2:查看集群状态;expect:执行成功----'
        self.log.info(text)
        q_res = self.common.get_sh_result(self.user_nodes[1], self.q_cmd)
        self.assertIn('cluster_state   : Normal', q_res, f'执行失败: {text}')

        text = '----step3:kill -9强制终止数据库进程;expect:强制终止数据库主进程成功----'
        self.log.info(text)
        kill_cmd = f"{self.ps_cmd}|awk '{{{{print $2}}}}'|" \
                   f"xargs -I {{{{}}}} kill -9 {{{{}}}};" \
                   f"{self.ps_cmd}"
        kill_res = self.common.get_sh_result(self.user_nodes[0], kill_cmd)
        self.assertNotIn('error', kill_res.lower(), f'执行失败: {text}')

        text = '----step4:查看数据库主进程;expect:数据库主节点已被拉起----'
        self.log.info(text)
        for i in range(10):
            time.sleep(5)
            q_res = self.common.get_sh_result(self.user_nodes[0], self.ps_cmd)
            if len(q_res.strip()) > 0:
                break
        self.assertGreater(len(q_res.strip()), 0, f'执行失败: {text}')

        text = '----step5:查看主节点事务执行情况;expect:主节点事务阻塞----'
        self.log.info(text)
        pri_thread.join(1)
        pri_res = pri_thread.get_result()
        self.log.info('结果可能为None，也可能返回连接失败信息')
        self.log.info(f'pri_res:{pri_res}')
        if pri_res:
            self.assertIn('failed to connect', '\n'.join(pri_res),
                          f'执行失败: {text}')

    def tearDown(self):
        text = '----poststep1:还原集群;expect:执行成功----'
        self.log.info(text)
        q_res = ''
        for i in range(10):
            time.sleep(10)
            q_res = self.common.get_sh_result(self.user_nodes[0], self.q_cmd)
            if 'Primary Normal' in q_res.splitlines()[-1].split('|')[0]:
                break
            elif 'Standby Normal' in q_res.splitlines()[-1].split('|')[0]:
                switch_cmd = f"source {macro.DB_ENV_PATH};cm_ctl switchover -a;"
                self.common.get_sh_result(self.user_nodes[0], switch_cmd)
                time.sleep(5)
                q_res = self.common.get_sh_result(
                    self.user_nodes[0], self.q_cmd)

        text = '----poststep2:删除表;expect:执行成功----'
        self.log.info(text)
        sql = f"drop table if exists {self.t_name} cascade;"
        sql_res = self.pri_sh.execut_db_sql(sql)
        self.log.info(sql_res)

        text = '----poststep3:卸载cm;expect:执行成功----'
        self.log.info(text)
        self.un_cm = CmUnInstall(self.install_pkg_path,
                                 self.pri_sh.node.ssh_user)
        res = self.un_cm.cm_uninstall(
            self.user_nodes[0], '--deleteData --deleteBinary')

        self.assertTrue(
            'Primary Normal' in q_res and q_res.count('Standby Normal') == 2,
            f'执行失败: {text}')
        self.assertIn(self.constant.DROP_TABLE_SUCCESS, sql_res,
                      f'执行失败: {text}')
        self.assertIn('Uninstall CM tool success', res, f'执行失败: {text}')
        self.log.info(f'-----{os.path.basename(__file__)} end-----')
